//* --------------------------------------------
//* Draw Loop ----------------------------------
//* --------------------------------------------
//* --------------------------------------------


// call the draw functions
void draw(){

  // background color (light-grey)
  background(0x00000000);
  
  // show the plot area as a white box
  //fill(0x00000000);
  noFill();
  rectMode(CORNERS);
  noStroke();

  drawPlotBounds();
  
  drawGrid();
  
  //println("plot bounds drawn");
  drawOldPlot();
  drawPlot();
  
  
  //println("plot drawn");
  //drawPlot(); // hack
  //drawPlot();
  
  
  //println("label drawn");
  //strokeLayer();
  updateIntegrators();
  
  //println("integrators updated");
  
  //checkIntegrators();
  
  //println("integrators checked");

  // controls
  drawControls();
  
  // options
  drawOptions(optionX1, optionX2, optionY1, optionY2, nOption, selectedOption, optionLabel);
  drawOptions(coloringX1, coloringX2, coloringY1, coloringY2, nColoring, selectedColoring, coloringLabel);
  
  //time line
  drawTimeline();
  
  //println("controls drawn");
  
  //Filter tabs
  drawFilterTabs();
  
  
  //println("filter tabs drawn");
  
  drawGridSmaller();
  if(!drawTrend()) drawLabel();
  
//  for(int i=0; i<controller.numLayers; i++)
//    computeBestLabelPosition(i);
  
  //colorLayers();
}

void drawOptions(float x1, float x2, float y1, float y2, int n, int selected, String[] labels) {
  
  float gridY = (y2 - y1) / n;
  stroke(255);
  for (int i = 0; i != n; ++i) {
    // circle
    strokeWeight(1);
    noFill();
    ellipse(x1+5, y1+i*gridY, 10, 10);
    if(selected == i) {
      strokeWeight(5);
      point(x1+5, y1+i*gridY);
    }
    // label
    textAlign(LEFT, CENTER);
    //textSize(10);
    textFont(filterFont);
    fill(0xBBF0F0F0);
    text(labels[i], x1+30, y1+i*gridY);
  }
}

void drawTimeline() {
  
  // time line
  stroke(255);
  stroke(0x99F0F0F0);
  strokeWeight(1);
  line(timeLineX1, timeLineY, timeLineX2, timeLineY);
  
  // labels
  int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
  int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  int iYear1 = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
  int iYear2 = (int)map(rtimeSliderPos,  timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
  
  float lenText = 7*7;//years[0].length();
  float preX = -1;
  for(int pos = low; pos < upper; pos++){
    
    float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
    
    if( preX == -1 || x - preX >= lenText ) {
      strokeWeight(2);
      //stroke(255); 
      line(x, timeLineY - 3.5, x, timeLineY + 3.5);
      
      if(pos == highlightedPointPos) { preX = x; continue;}
      int iYear = floor( map(pos, low, upper - 1, iYear1, iYear2) );
      fill(0x99F0F0F0);
      textSize(9);
      textAlign(CENTER, TOP);
      String month = years[iYear].split("-")[1];
      String year = years[iYear].split("-")[0];
      text(month + "/" + year, x, timeLineY + 5);
      preX = x;
    } else {
      strokeWeight(1);
      //stroke(255); 
      line(x, timeLineY - 1.5, x, timeLineY + 1.5);
    }
    
    
  }
  
  if(highlightedPoint!= -1) {
      // the point
      int pos = highlightedPointPos;
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      
      int iYear = floor( map(pos, low, upper - 1, iYear1, iYear2) );
      fill(0xBBF0F0F0);
      textSize(11);
      
      textAlign(CENTER, TOP);
      String month = years[iYear].split("-")[1];
      String year = years[iYear].split("-")[0];
      text(month + "/" + year, x, timeLineY + 15);
      
  }
  
}



void drawGrid() {
  
  // labels
  int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
  int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  int iYear1 = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
  int iYear2 = (int)map(rtimeSliderPos,  timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
  
  float preX = -1;
  float preXx = -1;
  for(int pos = low; pos < upper; pos++){
    float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
    float lenText = 7*7;//years[0].length();
    if( preX == -1 || x - preX >= lenText ) {
      
      if(preXx == -1 || x - preXx >= (-mainPlotX1 + mainPlotX2)/6){
        strokeWeight(2);
  
        stroke(0x2FFFFFFF);
        dottedLine(x, timeLineY, x, mainPlotY1, 3, 4);
        preXx = x;
      } 
      preX = x;
    } 
    
    
  }
  
  
  if(highlightedPoint!= -1) {
      // the point
      int pos = highlightedPointPos;
      
      stroke(0x1FFFFFFF);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      dottedLine(x, timeLineY, x, mainPlotY1, 3, 4);

  }
  
}


void drawGridSmaller() {
  
  // labels
  int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
  int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  int iYear1 = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
  int iYear2 = (int)map(rtimeSliderPos,  timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
  
  float preX = -1;
  float preXx = -1;
  for(int pos = low; pos < upper; pos++){
    float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
    float lenText = 7*7;//years[0].length();
    if( preX == -1 || x - preX >= lenText ) {
      
      if(preXx == -1 || x - preXx >= (-mainPlotX1 + mainPlotX2)/6){
        strokeWeight(2);
  
        stroke(0x2FFFFFFF);
        dottedLine(x, timeLineY, x, timeLineY - 25, 3, 4);
        preXx = x;
      } 
      preX = x;
    } 
    
    
  }
  
  
  if(highlightedPoint!= -1) {
      // the point
      int pos = highlightedPointPos;
      
      stroke(0x1FFFFFFF);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      dottedLine(x, timeLineY, x, timeLineY - 25, 3, 4);

  }
  
}

void drawLabel() {  
  
  // draw other labels  
  for (int layerID = 0; layerID < controller.numLayers; layerID++) {
    if(highlightedLayer == layerID && !withinFilterBounds()) continue;
    
    noStroke();
    
    float max_offset = 0; //controller.getg0(0) + controller.getUpperOffset(layerID, 0) - controller.getg0(0) - controller.getLowerOffset(layerID, 0);
    float value_max_offset = 0; //controller.getg0(0) + controller.getUpperOffset(layerID, 0) + max_offset/2;
    int pos_max_offset = 0;
    
    
    float max_width = 0;
    float pos_max_width = 0;
    float value_max_width = 0;
    
//    int upper = numDivisions;
//    if((numData / numDivisions) == 0)
//    upper = numData;
    
    float der_aft_up = 0;
    float der_bef_up = 0;
    
    float der_aft_low = 0;
    float der_bef_low = 0;
    
    int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
    int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);  
    
    for(int pos = low + 2; pos < upper - 2; pos++){
      float value_u =  controller.getUpperData(layerID, pos);//controller.getg0(pos) + controller.getUpperOffset(layerID, pos);//controller.getUpperData(layerID, pos);
      float value_l =  controller.getLowerData(layerID, pos); //controller.getg0(pos) + controller.getLowerOffset(layerID, pos);//controller.getLowerData(layerID, pos);
      float offset = value_u - value_l;
      if(offset > max_offset) {
        max_offset = offset;
        pos_max_offset = pos;
        value_max_offset = value_l + offset/2 - 2;
        
        float value_bef =  controller.getUpperData(layerID, pos - 1); //controller.getg0(pos - 1) + controller.getUpperOffset(layerID, pos - 1);
        float value_aft =  controller.getUpperData(layerID, pos + 1);//controller.getg0(pos + 1) + controller.getUpperOffset(layerID, pos + 1);
        
        der_bef_up = abs(value_u - value_bef);
        der_aft_up = abs(value_u - value_aft);
        
        value_bef =  controller.getLowerData(layerID, pos - 1); //controller.getg0(pos - 1) + controller.getLowerOffset(layerID, pos - 1);
        value_aft =  controller.getLowerData(layerID, pos + 1); //controller.getg0(pos + 1) + controller.getLowerOffset(layerID, pos + 1);
        
        der_bef_low = abs(value_l - value_bef);
        der_aft_low = abs(value_l - value_aft);
      }
      
    }
    
//    float x1 = map(pos_max_offset, 0, upper, mainPlotX1, mainPlotX2);      
//    float y1 = map(controller.getg0(pos_max_offset) + controller.getUpperOffset(layerID, pos_max_offset), dataMin, dataMax, mainPlotY1 , mainPlotY2);
//    noFill();
//    stroke(0xFFFFFFFF);
//    drawLayer(layerID, upper);
//    stroke(0xFFFFFFFF);
//    strokeWeight(10);
//    point(x1, y1);
//    strokeWeight(1);
    
//    if(layerID == 7){
//      print( "id: " + layerID + " " + data.getColumnName(controllerOld.matchLayerIDReverse(layerID)) + " : "  + "pos_max_offset : " + pos_max_offset + " -> "  );
//      //println("der_bef_up: " + der_bef_up + "der_aft_up: " + der_aft_up + "der_bef_low: " + der_bef_low + "der_aft_low: " + der_aft_low);
//    }
    
      
    if(pos_max_offset == 0) continue;
    boolean useHeight = true;
    float txtsize = max_offset / 4;
    if(der_bef_up  < dataMax * 0.1 &&  der_aft_up < dataMax * 0.1 && der_aft_low < dataMax * 0.1 && der_bef_low < dataMax * 0.1) txtsize = max_offset / 1 ;
    else if((der_bef_up < dataMax * 0.1 &&  der_aft_up < dataMax * 0.1) || (der_aft_low < dataMax * 0.1 && der_bef_low < dataMax * 0.1)) txtsize = max_offset / 1.5 ;
    else if(der_bef_up < dataMax * 0.1 ||  der_bef_up < dataMax * 0.1 || der_aft_low < dataMax * 0.1 || der_bef_low < dataMax * 0.1) txtsize = max_offset / 3 ;
    
    if(der_bef_up > dataMax * 0.4  ||  der_aft_up > dataMax * 0.4 || der_aft_up > dataMax * 0.4 || der_bef_low > dataMax * 0.4 ) txtsize = max_offset / 3.5;
    
    if (der_aft_up > dataMax * 0.2 && der_bef_up < dataMax * 0.2) pos_max_offset = pos_max_offset - 1;
    if (der_aft_up < dataMax * 0.2 && der_bef_up > dataMax * 0.2) pos_max_offset = pos_max_offset + 1;
    if (der_aft_low > dataMax * 0.2 && der_bef_low < dataMax * 0.2) pos_max_offset = pos_max_offset - 1;
    if (der_aft_low < dataMax * 0.2 && der_bef_low > dataMax * 0.2) pos_max_offset = pos_max_offset + 1;
    
    if(value_max_offset > dataMax * 0.2){
      txtsize = max_offset / 4;
      if (der_aft_up > der_aft_low && der_bef_up > der_bef_low ) value_max_offset = value_max_offset - (der_aft_up > der_bef_up ? der_aft_up : der_bef_up) * 0.2;
      if (der_aft_up < der_aft_low && der_bef_up < der_bef_low ) value_max_offset = value_max_offset + (der_aft_low > der_bef_low ? der_aft_low : der_bef_low) * 0.2;
    }else {
      if(der_bef_up  < dataMax * 0.2 &&  der_aft_up < dataMax * 0.2 && der_aft_low < dataMax * 0.2 && der_bef_low < dataMax * 0.2) txtsize = max_offset / 1.5 ;    
    }
    

    
    
    if (txtsize > 6) {
      float x;
      float y;
      x = map(pos_max_offset, low, upper, mainPlotX1, mainPlotX2);      
      y = map(value_max_offset, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);   
      
      color c = controller.getColor(layerID);
      float r = red(c), g = green(c), b = blue(c);
      fill(color(r+80, g+80, b+80, 100));
      textAlign(CENTER, CENTER);
      textSize(txtsize);
      
      PFont labelFont = createFont("Verdana", txtsize);
      textFont(labelFont);
      if(layerID == 7){
         //println( "id: " + layerID + " " + data.getColumnName(controllerOld.matchLayerIDReverse(layerID)) + " : "  +   controllerOld.matchLayerIDReverse(layerID));
      }
      text(data.getColumnName(controllerOld.matchLayerIDReverse(controllerPrev.matchLayerIDReverse(layerID))), x, y);
    }
    
  }
  
  
  // 
  
  if(highlightedLayer == -1) return;
  if(withinFilterBounds()) return;
  
  String name = data.getColumnName(controllerOld.matchLayerIDReverse(controllerPrev.matchLayerIDReverse(highlightedLayer)));
  int w = 0;
  for(int i=0; i< controller.numLayers; i++){
    String s = (data.getColumnName(controllerOld.matchLayerIDReverse(controllerPrev.matchLayerIDReverse(i))));
    int n = s.length();
    if( w < n ) w = n;
  }
  
  w = w * 10;
  // draw the dialog
  strokeWeight(2);
  color c = controller.getColor(highlightedLayer);
  float r = red(c), g = green(c), b = blue(c);
  
  fill(color(r+50, g+50, b+50, 205));
  stroke(255, 0.7*255);
  
  if( r >= 150 && g >= 150 && b >= 150)  stroke(0, 0.7*255);
  int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
  //int w = 200;//name.length() * 15 + 20;
  int h = 40;
  if(mouseX + w + 50 > mainPlotX2) {
    x1 = mouseX - 280; x2 = x1 + w;
    y1 = mouseY + 20; y2 = mouseY + 120;
  } else if(mouseY + h + 50> mainPlotY2 ) {
    x1 = mouseX + 40; x2 = mouseX + 280;
    y1 = mouseY - 120; y2 = mouseY - 20;
  } else {
    x1 = mouseX + 40; x2 = mouseX + 280;
    y1 = mouseY + 20; y2 = mouseY + 120;
  }
  rectMode(CORNER);
  rect(x1, y1, w, h, 20);
  textAlign(CENTER, CENTER);
  
  fill(color(r+50, g+50, b+50, 255));
  //fill(0);
  fill(255, 0.7*255);
  if( r >= 150 && g >= 150 && b >= 150)  fill(0, 0.7*255);
  textSize(15);
  
  PFont hoverFont = createFont("Verdana", 15);
  textFont(hoverFont);
      
  text(name, (x1 + x1 + w)/2, (y1 + y1 + h)/2);
}

void drawPlotBounds(){
  rect(mainPlotX1, mainPlotY1, mainPlotX2, mainPlotY2);
}

void drawPlot(){

   int upper = numDivisions;
   if((numData / numDivisions) == 0)
    upper = numData;
    
  int layerIDReal = -1;
  int layerIDRealHighlight = -1;

  for (int layerID = 0; layerID < controller.numLayers/2; layerID++) {
//    if(controller.matchLayerID(layerIDtoStroke) == layerID) {layerIDReal = layerID; continue;}
//    if(controller.matchLayerID(highlightedLayer) == layerID) {layerIDRealHighlight = layerID; continue;}
    if(layerIDtoStroke == layerID) {layerIDReal = layerID; continue;}
    if(highlightedLayer == layerID) {layerIDRealHighlight = layerID; continue;}
    stroke(controller.getStrokeColor(layerID));
    strokeWeight(2);
    //noStroke();
    fill(controller.getColor(layerID));
    //noFill();
    //drawLayer(layerID, upper);
    if(layerID != highlightedPoint) drawLayerNew(layerID);
  }
  
  for (int layerID = controller.numLayers - 1; layerID >= ceil(controller.numLayers/2); layerID--) {
    if(layerIDtoStroke == layerID) {layerIDReal = layerID; continue;}
    if(highlightedLayer == layerID) {layerIDRealHighlight = layerID; continue;}
    color c = controller.getStrokeColor(layerID);
    stroke(controller.getStrokeColor(layerID));
    strokeWeight(2);
    //noStroke();
    fill(controller.getColor(layerID));
    //noFill();
    //drawLayer(layerID, upper);
    if(layerID != highlightedPoint) drawLayerNew(layerID);
  }
  if(highlightedPoint != -1) drawLayerNew(highlightedPoint);
  
  strokeWeight(2);
  strokeLayer(layerIDReal, upper);
  highlightLayer(layerIDRealHighlight, upper);  
}

void drawOldPlot(){
  int upper = numDivisions;
   if((numData / numDivisions) == 0)
    upper = numData;
    
  int layerIDReal = -1;
  int layerIDRealHighlight = -1;

  for (int layerID = 0; layerID < controllerOld.numLayers; layerID++) {
    if(filtersChosen[layerID] == 1) continue;
    stroke(controllerOld.getColor(layerID));
    strokeWeight(2);
    fill(controllerOld.getColor(layerID));
    drawStreamPlotFade(layerID);
  }
}

void strokeLayer(int layerID, int upper){
  
  if (layerIDtoStroke == -1) return;
  if (layerID == -1) return;
    
    println("in stroke");
   //int layerID = layerIDtoStroke;
    stroke(controller.getStrokeColor(layerIDtoStroke));
    strokeWeight(2);
    fill(controller.getColor(layerID));

    drawLayerNew(layerID);
    //drawLayer(layerID, upper);
  
}


void highlightLayer(int layerID, int upper){

   //println("In highlight layer first");
  if (highlightedLayer == -1) return;
  
   //println("In highlight layer before layer id");
  if (layerID == -1) return;
  
  
  //println("In highlight layer");
    
   //int layerID = layerIDtoStroke;
    stroke(controller.getHighlightColor(highlightedLayer));
    strokeWeight(2);
    if(withinFilterBounds()) strokeWeight(3);
    fill(controller.getColor(layerID));
    
    if(drawTrend()) {
       strokeWeight(5);
       //stroke(0xFFFFFFFF);
      }

    drawLayerNew(layerID);
    //drawLayer(layerID, upper);
    
//    if(highlightedLayer != -1 ){
//       fill(0xFFFFFFFF);
//        textAlign(CENTER, CENTER);
//        textSize(20);
//        text(data.getColumnName(highlightedLayer) + " : " + highlightedLayer + "\n " + 
//             data.getColumnName(controller.matchLayerIDReverse(highlightedLayer)) + " : " + controller.matchLayerIDReverse(highlightedLayer), width - 250, 30);
//     }
  
}

void drawLayer(int layerID, int upper){
    beginShape();
    
    for(int pos = 0; pos < upper; pos++){
      float value =  controller.getg0(pos) + controller.getUpperOffset(layerID, pos);//controller.getUpperData(layerID, pos);
      float x = map(pos, 0, upper, mainPlotX1, mainPlotX2);
      float y = map(value, dataMin, dataMax, mainPlotY1 , mainPlotY2);

      curveVertex(x, y);
      //else vertex(x, y);
      if(pos == 0) curveVertex(x, y);
        
      
    }
    
    for(int pos = upper-1; pos >= 0; pos--){
      float value =  controller.getg0(pos) + controller.getLowerOffset(layerID, pos);//controller.getLowerData(layerID, pos);
      float x = map(pos, 0, upper, mainPlotX1, mainPlotX2);      
      float y = map(value, dataMin, dataMax, mainPlotY1 , mainPlotY2);
      curveVertex(x, y);

        if(pos == 0) curveVertex(x, y);
    }
    endShape();
  
}


void drawLayerNew(int layerID){
  if(drawTrend()) {
    noFill();
    if(layerID != highlightedLayer) strokeWeight(1);
    drawTrendPlot(layerID);
  }else drawStreamPlot(layerID);
  
  
  
}

void drawTrendPlot(int layerID){
  
  stroke(controller.getStrokeColor(layerID));
  
  int strokebase = 2;
  if(highlightedPoint == layerID) {
    strokebase = 4;
  }
  
  color c = controller.getStrokeColor(layerID);
  
  float r = red(c); float g = green(c); float b = blue(c);
  
  
  if(highlightedPoint != -1 && highlightedPoint != layerID)  {
    stroke(color(r - 20, g- 20, b- 20, 160));
    if(r >= 150 && g >= 150 && b>= 150) stroke(color(r - 90, g- 90, b- 90, 120));
  }
  
  if(!withinFilterBounds()) strokeWeight(strokebase);
  beginShape();

    //calculate range first
    int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
    int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  
    
    for(int pos = low; pos < upper; pos++){
     
      float value =  controller.getUpperData(layerID, pos) - controller.getLowerData(layerID, pos);//controller.getRealData(layerID, pos);//controller.getUpperData(layerID, pos);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      float y = map(value, 0, computeTrendDataMax(), mainPlotY2 - 20, mainPlotY1 + 20);

      vertex(x, y);
      
    }

    endShape(); 
    
    
//    for(int pos = low; pos < upper; pos++){
//     
//      float value =  controller.getUpperData(layerID, pos) - controller.getLowerData(layerID, pos); //controller.getRealData(layerID, pos);//controller.getUpperData(layerID, pos);
//      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
//      float y = map(value, 0, computeTrendDataMax(), mainPlotY2 - 20, mainPlotY1 + 20);
//
//      point(x, y);
//      
//    } 
    
    
  if(highlightedPoint != layerID) {
    strokebase = 2;
  }
 
    
    strokeWeight(strokebase+5);
    // highlighted point
    if(highlightedPoint!= -1) {
      // the point
      int pos = highlightedPointPos;
      float value = controller.getUpperData(layerID, pos) - controller.getLowerData(layerID, pos);
      
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      float y = map(value, 0, computeTrendDataMax(), mainPlotY2 - 20, mainPlotY1 + 20);
      
      strokeWeight(strokebase);
      fill(255);  
      if(highlightedPoint == layerID)
        ellipse(x, y, 14, 14);
      // the label
      else 
        ellipse(x, y, 8, 8);
      if(highlightedPoint == layerID)
        textAlign(CENTER, BOTTOM);
      String name = data.getColumnName(controllerOld.matchLayerIDReverse(controllerPrev.matchLayerIDReverse(layerID)));
      int iYear1 = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
      int iYear2 = (int)map(rtimeSliderPos,  timeScrollBarX1, timeScrollBarX2, 0, data.rowCount - 1);
      int iYear = floor( map(pos, low, upper - 1, iYear1, iYear2) );
      String month = years[iYear].split("-")[1];
      String year = years[iYear].split("-")[0];       
      float x2 = x;
      float y2 = y;
      if(x2 - 80 < mainPlotX1) x2 = x2 + 80;
      if(x2 + 80 > mainPlotX2) x2 = x2 - 80;
      if(y2 - 80 < mainPlotY1) y2 = y2 + 80;
      
      if(layerID != highlightedPoint) textSize(8);
      else textSize(10);
      text(name + ": " + round(value) /*+ " - " + month + "/" + year*/, x2, y2 - 20); textAlign(CENTER, BOTTOM);
    }
}


void drawStreamPlot(int layerID){
 beginShape();
    
    //calculate range first
    int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
    int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  
    
    for(int pos = low; pos < upper; pos++){
      float value =  controller.getUpperData(layerID, pos);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      float y = map(value, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);

      curveVertex(x, y);
      //else vertex(x, y);
      if(pos == low) curveVertex(x, y);
      
    }

    for(int pos = upper-1; pos >= low; pos--){
      float value =  controller.getLowerData(layerID, pos);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);      
      float y = map(value, dataMin, dataMax, mainPlotY2 -20, mainPlotY1 + 20);
      curveVertex(x, y);

        if(pos == low) curveVertex(x, y);
    }
    endShape(); 
    
    
//    // highlighted point
//    if(layerID == highlightedLayer) {
//      // draw point
//      if(highlightedPoint == 1) {
//        int highlightedPos = (int)map(mouseX, mainPlotX1, mainPlotX2, low, upper - 1);
//        for(int pos = low; pos < upper; pos++){
//          if(pos == highlightedPos) {          
//            float value =  controller.getg0(pos) + controller.getUpperOffset(highlightedLayer, pos);//controller.getUpperData(layerID, pos);
//            float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
//            float y = map(value, dataMin, dataMax, mainPlotY2 , mainPlotY1);
//            
//            
//            color c = controller.getColor(highlightedLayer);
//            stroke(color(red(c)+80, green(c)+80, blue(c)+80));
//            fill(c);
//            ellipse(x, y, 10, 10);
//            break;
//          }        
//        }
//      }
//    }  
    
//    // highlighted point
//    if(layerID == highlightedLayer) {
//      // fill(controller.getColor(layerID));
//      if(highlightedPoint == 1) {
//        int highlightedPos = (int)map(mouseX, mainPlotX1, mainPlotX2, low, upper - 1);
//        for(int pos = low; pos < upper; pos++){
//          if(pos == highlightedPos) {          
//            float value =  controller.getg0(pos) + controller.getUpperOffset(highlightedLayer, pos);//controller.getUpperData(layerID, pos);
//            float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
//            float y = map(value, dataMin, dataMax, mainPlotY2 , mainPlotY1);
//            
//            color c = controller.getColor(highlightedLayer);
//            stroke(color(red(c)+80, green(c)+80, blue(c)+80));
//            fill(c);
//            ellipse(x, y, 10, 10);
//            break;
//          }        
//        }
//      }
//    }  
    
}

void drawStreamPlotFade(int layerID){
 beginShape();
    
    //calculate range first
    int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
    int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  
    
    for(int pos = low; pos < upper; pos++){
      float value =  controllerOld.getUpperData(layerID, pos);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      float y = map(value, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);

      curveVertex(x, y);
      //else vertex(x, y);
      if(pos == low) curveVertex(x, y);
      
    }

    for(int pos = upper-1; pos >= low; pos--){
      float value =  controllerOld.getLowerData(layerID, pos);
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);      
      float y = map(value, dataMin, dataMax, mainPlotY2 -20, mainPlotY1 + 20);
      curveVertex(x, y);

        if(pos == low) curveVertex(x, y);
    }
    endShape(); 
}


void drawFilterTabs(){
//  fill(0);
//  textSize(20);
//  textAlign(CENTER);
//  String title = "Color Picker";
//  text(title, plotX3 + (plotX4 - plotX3) * 0.5, plotY3 - 10);
  
  rectMode(CORNER);
  // show the plot area as a white box
  int num =0;
  float dimy = (filterY2 - filterY1) / numFilters;
    for(int j=numFilters-1; j >= 0; j--){
//      stroke(0xFFFFFFFF);
      strokeWeight(1);
      textAlign(LEFT, TOP);
      if(filtersChosen[numFilters - 1 - j] == 1)
        fill(0xBBF0F0F0);
      else
        fill(0x66F0F0F0);
      textSize(10);
      
//      if(highlightedLayer != -1) {
//        if(highlightedLayer == controller.matchLayerID(numFilters - 1 - j)) {
//          fill(0xFFFFFFFF);
//        } else {
//          if(filtersChosen[numFilters - 1 - j] == 1) fill(0xBBF0F0F0);
//          else fill(0x66F0F0F0);
//        }
//      } else {
//        if(filtersChosen[numFilters - 1 - j] == 1) fill(0xBBF0F0F0);
//        else
//          fill(0x66F0F0F0);
//      }
      
      
      if(withinFilterBounds()){
          int k = floor( (mouseY-filterY1)/dimy);
          
          //k = numFilters - k - 1;
          
          if(k == j) fill(0xFFFFFFFF);
    
      }
      textFont(filterFont);
      text(data.getColumnName(controllerOld.matchLayerIDReverse(numFilters - 1 - j)), filterX1 + 30, filterY1 + j*dimy);
      noFill();
      
      if(controller.matchLayerID(numFilters - 1 - j) != -1){
        color c = controller.getColor(controller.matchLayerID(numFilters - 1 - j));
        float r = red(c), g = green(c), b = blue(c);
        fill(color(r, g, b, 255));
        stroke(0xBBF0F0F0);
      } else
        stroke(0x66F0F0F0);
      
      rect(filterX1, filterY1 + j*dimy, checkBoxDim, checkBoxDim);
      
      //stroke(0xFFFFFFFF);
      //if(filtersChosen[j] == 1)
      //line(filterX1 + 3, filterY1 + j*dimy + 3, filterX1 + checkBoxDim - 3, filterY1 + j*dimy + checkBoxDim - 3);
    }
 }
 
 
 
 
 
 
 
void drawHueFlip(){
  noFill();
  if(isHueFlip == 3){
    arc(hueFlipPosX, hueFlipPosY, hueFlipDim, hueFlipDim, 0, PI+HALF_PI + QUARTER_PI / 2, OPEN);
    line(hueFlipPosX - 1, hueFlipPosY - 3, hueFlipPosX + 2, hueFlipPosY - hueFlipDim/2);
    line(hueFlipPosX - 1, hueFlipPosY - hueFlipDim/2 - 3, hueFlipPosX + 2, hueFlipPosY - hueFlipDim/2);
  }else if(isHueFlip == 0){
    arc(hueFlipPosX, hueFlipPosY, hueFlipDim, hueFlipDim, PI + QUARTER_PI, PI + QUARTER_PI + PI + HALF_PI + QUARTER_PI / 2, OPEN);
    line(hueFlipPosX - 1, hueFlipPosY - 3, hueFlipPosX - 4, hueFlipPosY - hueFlipDim/2);
    line(hueFlipPosX - 1, hueFlipPosY - hueFlipDim/2 - 3, hueFlipPosX - 4, hueFlipPosY - hueFlipDim/2);
    //line(hueFlipPosX - 1, hueFlipPosY - 3, hueFlipPosX + 2, hueFlipPosY - hueFlipDim/2);
    //line(hueFlipPosX - 1, hueFlipPosY - hueFlipDim/2 - 3, hueFlipPosX + 2, hueFlipPosY - hueFlipDim/2);
  } 
  else if(isHueFlip == 1){
    line(hueFlipPosX + hueFlipDim/2 - 4, hueFlipPosY - hueFlipDim/2 + 1, hueFlipPosX + hueFlipDim/2, hueFlipPosY);
    line(hueFlipPosX + hueFlipDim/2 - 4, hueFlipPosY + hueFlipDim/2 - 1, hueFlipPosX + hueFlipDim/2, hueFlipPosY);
    line(hueFlipPosX - hueFlipDim/2, hueFlipPosY , hueFlipPosX + hueFlipDim/2, hueFlipPosY);
  }else{
    line(hueFlipPosX - hueFlipDim/2, hueFlipPosY, hueFlipPosX + hueFlipDim/2, hueFlipPosY);
    line(hueFlipPosX - hueFlipDim/2 + 4, hueFlipPosY - hueFlipDim/2 + 1, hueFlipPosX - hueFlipDim/2, hueFlipPosY);
    line(hueFlipPosX - hueFlipDim/2 + 4, hueFlipPosY + hueFlipDim/2 - 1, hueFlipPosX - hueFlipDim/2, hueFlipPosY);
  }
}

void drawLumaFlip(){
  noFill();
  if(isLumaFlip == 1){
    arc(lumaFlipPosX, lumaFlipPosY, lumaFlipDim, lumaFlipDim, 0, PI+HALF_PI + QUARTER_PI / 2, OPEN);
    line(lumaFlipPosX - 1, lumaFlipPosY - 3, lumaFlipPosX + 2, lumaFlipPosY - lumaFlipDim/2);
    line(lumaFlipPosX - 1, lumaFlipPosY - lumaFlipDim/2 - 3, lumaFlipPosX + 2, lumaFlipPosY - hueFlipDim/2);
  }else{
    arc(lumaFlipPosX, lumaFlipPosY, lumaFlipDim, lumaFlipDim, PI + QUARTER_PI, PI + QUARTER_PI + PI + HALF_PI + QUARTER_PI / 2, OPEN);
    line(lumaFlipPosX - 1, lumaFlipPosY - 3, lumaFlipPosX - 4, lumaFlipPosY - lumaFlipDim/2);
    line(lumaFlipPosX - 1, lumaFlipPosY - lumaFlipDim/2 - 3, lumaFlipPosX - 4, lumaFlipPosY - lumaFlipDim/2);
  }
}

void drawChromaFlip(){
  noFill();
  if(isChromaFlip == 1){
    arc(chromaFlipPosX, chromaFlipPosY, chromaFlipDim, chromaFlipDim, 0, PI+HALF_PI + QUARTER_PI / 2, OPEN);
    line(chromaFlipPosX - 1, chromaFlipPosY - 3, chromaFlipPosX + 2, chromaFlipPosY - chromaFlipDim/2);
    line(chromaFlipPosX - 1, chromaFlipPosY - chromaFlipDim/2 - 3, chromaFlipPosX + 2, chromaFlipPosY - chromaFlipDim/2);
  }else{
    arc(chromaFlipPosX, chromaFlipPosY, chromaFlipDim, chromaFlipDim, PI + QUARTER_PI, PI + QUARTER_PI + PI + HALF_PI + QUARTER_PI / 2, OPEN);
    line(chromaFlipPosX - 1, chromaFlipPosY - 3, chromaFlipPosX - 4, chromaFlipPosY - chromaFlipDim/2);
    line(chromaFlipPosX - 1, chromaFlipPosY - chromaFlipDim/2 - 3, chromaFlipPosX - 4, chromaFlipPosY - chromaFlipDim/2);
    
  }
}

void drawTimeScrollBar(){
  rect(timeScrollBarX1, timeScrollBarY1, timeScrollBarX2, timeScrollBarY2);
  fill(0xFF223875);
  
   float n = controller.numLayers;
  
    int layerID = controller.numLayers - 1;
    float hue = getHue(n, true);
    float luma = getLuma(n, true);
    float chroma = getChroma(n, true);
    float []rgb = new float[3];

    HCLtoRGB(hue, 0.4, 0.5, rgb);
    fill(color(rgb[0], rgb[1], rgb[2], 255));  
  
  
  rect(ltimeSliderPos, timeScrollBarY1, rtimeSliderPos, timeScrollBarY2);
  textSize(8);
  fill(0xFFFFFFFF);
  textAlign(LEFT, CENTER);
  text("PAN & ZOOM", timeScrollBarX1 + 20, timeScrollBarY1 + (timeScrollBarY2 - timeScrollBarY1) / 2);
//  if(greyTimeBarOut){
//    //println("*********greyOut");
//    fill(0x99F0F0F0);
//    rect(timeScrollBarX1, timeScrollBarY1, timeScrollBarX2, timeScrollBarY2);
//  }
  
}

void drawTimeSliders(){
  rect(ltimeSliderPos - timeSliderDimX/2, timeSliderPosY, timeSliderDimX, timeSliderDimY);
  rect(rtimeSliderPos - timeSliderDimX/2, timeSliderPosY, timeSliderDimX, timeSliderDimY);
}

void drawHueScrollBar(){
//  rect(hueScrollBarX1, hueScrollBarY1, hueScrollBarX2, hueScrollBarY2);
//  fill(0xFF223875);
//  rect(lhueSliderPos, hueScrollBarY1, rhueSliderPos, hueScrollBarY2);
  int wHue = hueScrollBarX2 - hueScrollBarX1;
 
  if(isHueFlip == 0 || isHueFlip == 2){
  for(int i=0; i <= wHue; i++){

      float []rgb = new float[3];
      if(hueScrollBarX1 + i < lhueSliderPos || hueScrollBarX1 + i > rhueSliderPos)
        HCLtoRGB(map(i, 0, wHue, 0, 1), 0.5, 1, rgb);
      else
        HCLtoRGB(map(i, 0, wHue, 0, 1), 1, 0.5, rgb);
      stroke(rgb[0], rgb[1], rgb[2]);
      line(hueScrollBarX1 + i, hueScrollBarY1 + 1, hueScrollBarX1 + i, hueScrollBarY2 - 1);
    }
  }else{
    
    for(int i=0; i <= wHue; i++){

      float []rgb = new float[3];
      if(hueScrollBarX1 + i < lhueSliderPos || hueScrollBarX1 + i > rhueSliderPos)
        HCLtoRGB(map(i, 0, wHue, 1, 0), 0.5, 1, rgb);
      else
        HCLtoRGB(map(i, 0, wHue, 1, 0), 1, 0.5, rgb);
      stroke(rgb[0], rgb[1], rgb[2]);
      line(hueScrollBarX1 + i, hueScrollBarY1 + 1, hueScrollBarX1 + i, hueScrollBarY2 - 1);
    }
  }
  
  textSize(8);
  fill(0xFF000000);
  textAlign(LEFT, CENTER);
  text("HUE", hueScrollBarX1 + 20, hueScrollBarY1 + (hueScrollBarY2 - hueScrollBarY1) / 2);
  
}

void drawHueSliders(){
  rect(lhueSliderPos - hueSliderDimX/2, hueSliderPosY, hueSliderDimX, hueSliderDimY);
  rect(rhueSliderPos - hueSliderDimX/2, hueSliderPosY, hueSliderDimX, hueSliderDimY);
}



void drawLumaScrollBar(){

  int wLuma = lumaScrollBarX2 - lumaScrollBarX1;
  
  float n = controller.numLayers;
  
  int layerID = controller.numLayers - 1;
  float hue = getHue(n, true);
 
  if(isLumaFlip == 0 || isLumaFlip == 2){
  for(int i=0; i <= wLuma; i++){

      float []rgb = new float[3];
      if(lumaScrollBarX1 + i < llumaSliderPos || lumaScrollBarX1 + i > rlumaSliderPos)
        HCLtoRGB(0, 0, map(i, 0, wLuma, 0, 1), rgb);
      else
        HCLtoRGB(hue, 0.7, map(i, 0, wLuma, 0, 1), rgb);
      stroke(rgb[0], rgb[1], rgb[2]);
      line(lumaScrollBarX1 + i, lumaScrollBarY1 + 1, lumaScrollBarX1 + i, lumaScrollBarY2 - 1);
    }
    
    textSize(8);
  //textFont(filterFont);
  fill(0xFFFFFFFF);
  textAlign(LEFT, CENTER);
  text("LUMA", lumaScrollBarX1 + 20, lumaScrollBarY1 + (lumaScrollBarY2 - lumaScrollBarY1) / 2);
  }else{
    
    for(int i=0; i <= wLuma; i++){

      float []rgb = new float[3];
      if(lumaScrollBarX1 + i < llumaSliderPos || lumaScrollBarX1 + i > rlumaSliderPos)
        HCLtoRGB(0, 0, map(i, 0, wLuma, 1, 0), rgb);
      else
        HCLtoRGB(hue, 0.7, map(i, 0, wLuma, 1, 0), rgb);
      stroke(rgb[0], rgb[1], rgb[2]);
      line(lumaScrollBarX1 + i, lumaScrollBarY1 + 1, lumaScrollBarX1 + i, lumaScrollBarY2 - 1);
    }
    
    textSize(8);
  fill(0xFF000000);
  textAlign(LEFT, CENTER);
  text("LUMA", lumaScrollBarX1 + 20, lumaScrollBarY1 + (lumaScrollBarY2 - lumaScrollBarY1) / 2);
  }
  
  
  
}


void drawLumaSliders(){
  rect(llumaSliderPos - lumaSliderDimX/2, lumaSliderPosY, lumaSliderDimX, lumaSliderDimY);
  rect(rlumaSliderPos - lumaSliderDimX/2, lumaSliderPosY, lumaSliderDimX, lumaSliderDimY);
}

//////


void drawChromaScrollBar(){

  int wChroma = chromaScrollBarX2 - chromaScrollBarX1;
  
  float n = controller.numLayers;
  
  int layerID = controller.numLayers - 1;
  float hue = getHue(n, true);
 
  if(isChromaFlip == 0 || isChromaFlip == 2){
  for(int i=0; i <= wChroma; i++){

      float []rgb = new float[3];
      
      
      
      
      if(chromaScrollBarX1 + i < lchromaSliderPos || chromaScrollBarX1 + i > rchromaSliderPos)
        HCLtoRGB(1, map(i, 0, wChroma, 0, 1), 1,  rgb);
      else
        HCLtoRGB(hue, map(i, 0, wChroma, 0, 1), 0.5, rgb);
      stroke(rgb[0], rgb[1], rgb[2]);
      line(chromaScrollBarX1 + i, chromaScrollBarY1 + 1, chromaScrollBarX1 + i, chromaScrollBarY2 - 1);
    }
    textSize(8);
  fill(0xFF000000);
  textAlign(LEFT, CENTER);
  text("CHROMA", chromaScrollBarX1 + 20, chromaScrollBarY1 + (chromaScrollBarY2 - chromaScrollBarY1) / 2);
  }else{
    
    for(int i=0; i <= wChroma; i++){

      float []rgb = new float[3];
      if(chromaScrollBarX1 + i < lchromaSliderPos || chromaScrollBarX1 + i > rchromaSliderPos)
        HCLtoRGB(1, map(i, 0, wChroma, 1, 0), 1, rgb);
      else
        HCLtoRGB(hue, map(i, 0, wChroma, 1, 0),0.5, rgb);
      stroke(rgb[0], rgb[1], rgb[2]);
      line(chromaScrollBarX1 + i, chromaScrollBarY1 + 1, chromaScrollBarX1 + i, chromaScrollBarY2 - 1);
    }
    textSize(8);
  fill(0xFF000000);
  textAlign(LEFT, CENTER);
  text("CHROMA", chromaScrollBarX1 + 20, chromaScrollBarY1 + (chromaScrollBarY2 - chromaScrollBarY1) / 2);
  }
  
  
}


void drawChromaSliders(){
  rect(lchromaSliderPos - chromaSliderDimX/2, chromaSliderPosY, chromaSliderDimX, chromaSliderDimY);
  rect(rchromaSliderPos - chromaSliderDimX/2, chromaSliderPosY, chromaSliderDimX, chromaSliderDimY);
}

/////

void drawNumDivScrollBar(){
  //rect(numDivSliderPos - timeSliderDimX/2, timeSliderPosY, timeSliderDimX, timeSliderDimY);
  rect(numDivScrollBarX1, numDivScrollBarY1, numDivScrollBarX2, numDivScrollBarY2);
  fill(0xFF223875);
  float n = controller.numLayers;
  
    int layerID = controller.numLayers - 1;
    float hue = getHue(n, true);
    float luma = getLuma(n, true);
    float chroma = getChroma(n, true);
    float []rgb = new float[3];

    HCLtoRGB(hue, 0.4, 0.5, rgb);
    fill(color(rgb[0], rgb[1], rgb[2], 255));  
  rect(numDivScrollBarX1, numDivScrollBarY1, numDivSliderPos, numDivScrollBarY2);
  
  textSize(8);
  fill(0xFFFFFFFF);
  textAlign(LEFT, CENTER);
  text("SAMPLE TIME", numDivScrollBarX1 + 20, numDivScrollBarY1 + (numDivScrollBarY2 - numDivScrollBarY1) / 2);
}

void drawNumDivSliders(){
  rect(numDivSliderPos - timeSliderDimX/2, numDivSliderPosY, timeSliderDimX, timeSliderDimY);
}

/////

void drawNumFiltersScrollBar(){
  //rect(numDivSliderPos - timeSliderDimX/2, timeSliderPosY, timeSliderDimX, timeSliderDimY);
  rect(numFiltersScrollBarX1, numFiltersScrollBarY1, numFiltersScrollBarX2, numFiltersScrollBarY2);
  fill(0xFF223875);
  float n = controller.numLayers;
  
    int layerID = controller.numLayers - 1;
    float hue = getHue(n, true);
    float luma = getLuma(n, true);
    float chroma = getChroma(n, true);
    float []rgb = new float[3];

    HCLtoRGB(hue, 0.4, 0.5, rgb);
    fill(color(rgb[0], rgb[1], rgb[2], 255));  
  rect(lnumFiltersSliderPos, numFiltersScrollBarY1, rnumFiltersSliderPos, numFiltersScrollBarY2);
  
  textSize(8);
  fill(0xFFFFFFFF);
  textAlign(LEFT, CENTER);
  text("FILTER BY RANK", numFiltersScrollBarX1 + 20, numFiltersScrollBarY1 + (numFiltersScrollBarY2 - numFiltersScrollBarY1) / 2);
}

//void drawNumFiltersSliders(){
//  rect(numFiltersSliderPos - timeSliderDimX/2, numFiltersSliderPosY, timeSliderDimX, timeSliderDimY);
//}

void drawNumFiltersSliders(){
  rect(lnumFiltersSliderPos - numFiltersSliderDimX/2, numFiltersSliderPosY, numFiltersSliderDimX, numFiltersSliderDimY);
  rect(rnumFiltersSliderPos - numFiltersSliderDimX/2, numFiltersSliderPosY, numFiltersSliderDimX, numFiltersSliderDimY);
}
